﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;



namespace whereIsTheDonutGame 
{
    public class Terrain : whereIsTheDonutGame.ITerrain
    {
        GraphicsDevice device;
        Texture2D heightMap;
        BasicEffect effect;
        Texture2D grass;
        donutGame game;
        public int terrainWidth, terrainHeight;
        public int TerrainWidth
        {
            get { return terrainWidth; }
        }
        public int TerrainHeight
        {
            get { return terrainHeight; }
        }

        int[] indices;
        VertexPositionNormalTexture[] vertices;
           
        public float[,] height;
        public float[,] Height
        {
            get { return height; }
        }

        public Boolean isValidPosition(Vector3 pos)
        {
            if (pos.X <= terrainWidth-1 && pos.X >= 1 && -pos.Z <= terrainHeight-1 && -pos.Z >= 1)
                return true;
            return false;
        }


        public Terrain(donutGame game, GraphicsDevice device, SamplerState sampler)
        {
            this.game = game;
            this.device = device;
            this.heightMap = donutGame.heightMap;
            terrainWidth = heightMap.Width;
            terrainHeight = heightMap.Height;

            //setUpHeight();
            loadHeightData(heightMap);
            setUpVertex();
            setUpIndex();
            setUpNormals();

            effect = new BasicEffect(device);
        }
        
        private void setUpVertex()
        {
            vertices = new VertexPositionNormalTexture[terrainWidth * terrainHeight];

            for (int x = 0; x < terrainWidth; x++)
            {
                for (int z = 0; z < terrainHeight; z++)
                {
                    vertices[x + z * (int)terrainWidth].Position = new Vector3(x, height[x, z], -z);
                    vertices[x + z * terrainWidth].TextureCoordinate.X = (float)x / 30.0f;
                    vertices[x + z * terrainWidth].TextureCoordinate.Y = (float)z / 30.0f;
                }
            }
        }
  
        private void setUpIndex()
        {
            indices = new int[(int)(terrainWidth - 1) * (int)(terrainHeight - 1) * 6];
            int currentIndex = 0;

            for (int x = 0; x < terrainWidth - 1; x++)
            {
                for (int z = 0; z < terrainHeight - 1; z++)
                {
                    int downLeft = (x + z * (int)terrainWidth);
                    int downRight = ((x + 1) + z * (int)terrainWidth);
                    int upLeft = (x + (z + 1) * (int)terrainWidth);
                    int upRight = ((x + 1) + (z + 1) * (int)terrainWidth);

                    indices[currentIndex++] = downLeft;
                    indices[currentIndex++] = upLeft;
                    indices[currentIndex++] = downRight;

                    indices[currentIndex++] = downRight;
                    indices[currentIndex++] = upLeft;
                    indices[currentIndex++] = upRight;
                }
            }
        }

        public void setUpHeight()
        {
            height = new float[(int)terrainWidth, (int)terrainHeight];
            for (int x = 0; x < terrainWidth; x++)
            {
                for (int z = 0; z < terrainHeight; z++)
                {
                    height[x, z] = 1.0f; // (float)Math.Sin(0.1 * x) + 10 * (float)Math.Cos(0.3 * z) + 5;
                }
            }
        }

        public void loadHeightData(Texture2D heightMap)
        {
            Color[] heightMapColors = new Color[(int)terrainWidth * (int)terrainHeight];
            heightMap.GetData(heightMapColors);

            height = new float[(int)terrainWidth, (int)terrainHeight];
            for (int x = 0; x < terrainWidth; x++)
                for (int y = 0; y < terrainWidth; y++)
                    height[x, y] = heightMapColors[x + y * (int)terrainWidth].R / 5.0f;
        }


        public void setUpNormals()
        {
            for (int i = 0; i < vertices.Length; i++)
            {
                vertices[i].Normal = new Vector3(0, 0, 0);
            }
            for (int i = 0; i < indices.Length / 3; i++)
            {
                int index1 = indices[i * 3];
                int index2 = indices[i * 3 + 1];
                int index3 = indices[i * 3 + 2];

                Vector3 side1 = vertices[index1].Position - vertices[index3].Position;
                Vector3 side2 = vertices[index1].Position - vertices[index2].Position;

                Vector3 normal = Vector3.Cross(side1, side2);

                vertices[index1].Normal += normal;
                vertices[index2].Normal += normal;
                vertices[index3].Normal += normal;
            }
            for (int i = 0; i < vertices.Length; i++)
            {
                vertices[i].Normal.Normalize();
            }
            
        }
        
        public void Render(Camera camera)
        {
            effect.EnableDefaultLighting();
            effect.TextureEnabled = true;
            effect.Texture = game.texture;

            effect.View = camera.ViewMatrix;
            effect.Projection = camera.ProjectionMatrix;

            effect.CurrentTechnique.Passes[0].Apply();

            device.DrawUserIndexedPrimitives<VertexPositionNormalTexture>(PrimitiveType.TriangleList,
                vertices, 0, vertices.Length, indices, 0, indices.Length/3);
        }        
    }
}
